package com.syh.jn.scm.infrastructure.repository.impl.upstream.sale;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.core.expction.DataModelException;
import com.syh.jn.scm.domain.supplier.entity.sale.SaleOrderItem;
import com.syh.jn.scm.domain.upstream.entity.sale.UpSaleOrder;
import com.syh.jn.scm.domain.upstream.entity.sale.UpSaleOrderItem;
import com.syh.jn.scm.domain.upstream.repository.sale.UpSaleOrderRepository;
import com.syh.jn.scm.dto.upstream.sale.SaleStatisticalAmountVo;
import com.syh.jn.scm.dto.upstream.sale.UpSaleOrderItemVo;
import com.syh.jn.scm.dto.upstream.sale.UpSaleOrderVo;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.infrastructure.repository.model.purchase.PurchaseOrderItemModel;
import com.syh.jn.scm.infrastructure.repository.model.purchase.PurchaseOrderModel;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderItemModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 上游销售订单仓储
 */
@Repository
public class UpSaleOrderRepositoryImpl extends AbstractAggregateRepository<UpSaleOrder, PurchaseOrderModel, Long> implements UpSaleOrderRepository {

  @Override
  public void update(UpSaleOrder upSaleOrder) {
    super.update(upSaleOrder);
    if (upSaleOrder.getItems() == null)
      return ;
    this.removeItem(upSaleOrder);
    this.saveOrderItems(upSaleOrder.getId(), upSaleOrder.getItems());
  }

  /**
   * 保存订单项方法
   *
   * @param purchaseOrderId
   * @param items
   */
  private void saveOrderItems(Long purchaseOrderId, List<UpSaleOrderItem> items) {
    items.stream().forEach(item -> {
      PurchaseOrderItemModel itemModel = new PurchaseOrderItemModel();
      ExtBeanUtils.copyProperties(item, itemModel);
      itemModel.setPurchaseOrderId(purchaseOrderId);
      this.hibernateTemplate.save(itemModel);
    });
  }

  @Override
  public UpSaleOrder getById(Long id) {
    UpSaleOrder upSaleOrder = super.getById(id);
    if (upSaleOrder == null) {
      return upSaleOrder;
    }
    upSaleOrder.setItems(this.getItemsByOrderId(id));
    return upSaleOrder;
  }

  @Override
  public UpSaleOrderVo getKeyView(Serializable key) {
    UpSaleOrderVo vo = super.getKeyView(key);
    if(vo == null)
      throw new BusinessException("数据异常，销售订单不存在");
    vo.setItems(transformUpPurchase(this.getItemsByOrderId(vo.getId())));
    return vo;
  }

  /**
   * 删除订单项
   *
   * @param upSales
   */
  private void removeItem(UpSaleOrder upSales) {
    StringBuffer hql = new StringBuffer();
    hql.append("from PurchaseOrderItemModel model where model.purchaseOrderId = ?");
    List<PurchaseOrderItemModel> itemModelList = (List<PurchaseOrderItemModel>) this.hibernateTemplate.find(hql.toString(), upSales.getId());
    itemModelList.stream().forEach(item -> {
      this.hibernateTemplate.delete(item);
    });
  }

  /**
   * 根据id查出明细
   *
   * @param id
   * @return
   */
  @Override
  public List<UpSaleOrderItem> getItemsByOrderId(Long id) {
    StringBuffer hql = new StringBuffer();
    hql.append("from PurchaseOrderItemModel model where model.purchaseOrderId = ?");
    List<PurchaseOrderItemModel> itemModelList = (List<PurchaseOrderItemModel>) this.hibernateTemplate.find(hql.toString(), id);
    List<UpSaleOrderItem> itemList = new ArrayList<>();
    itemModelList.stream().forEach(item -> {
      UpSaleOrderItem upSaleOrderItem = new UpSaleOrderItem();
      ExtBeanUtils.copyProperties(item, upSaleOrderItem);
      itemList.add(upSaleOrderItem);
    });
    return itemList;
  }

  @Override
  public void update(UpSaleOrder upSales, boolean updateItems) {
    super.update(upSales);
    if (updateItems) {
      this.removeItem(upSales);
      this.saveOrderItems(upSales.getId(), upSales.getItems());
    }
  }

  /**
   * 上传单据图片
   *
   * @param order
   */
  @Override
  public void upload(UpSaleOrder order) {
    super.update(order);
  }

  @Override
  public void updateOrderAndItems(UpSaleOrder order) {
    PurchaseOrderModel orderModel = this.hibernateTemplate.get(PurchaseOrderModel.class, order.getId());
    if(orderModel == null){
      throw new DataModelException("订单不存在");
    }
    ExtBeanUtils.copyProperties(order, orderModel);
    this.hibernateTemplate.update(orderModel);
    //更新订单项
    order.getItems().forEach(orderItem -> {
      PurchaseOrderItemModel model = this.hibernateTemplate.get(PurchaseOrderItemModel.class, orderItem.getId());
      if(model == null){
        throw new DataModelException("对应明细不存在");
      }
      ExtBeanUtils.copyProperties(orderItem, model);
      this.hibernateTemplate.update(model);
    });
  }

  @Override
  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    Map<String, String> params = new HashMap<>();
    params.put("id", "upSales.ID");
    params.put("code", "upSales.CODE");
    params.put("deliName", "upSales.DELI_NAME");
    params.put("deliTel", "upSales.DELI_TEL");
    params.put("ordState", "upSales.ORD_STATE");
    params.put("deliveryState", "upSales.DELIVERY_STATE");
    params.put("collectState", "upSales.COLLECT_STATE");
    params.put("upStreamCompanyId", "upSales.UP_STREAM_COMPANY_ID");
    params.put("businessEntityId", "upSales.UP_STREAM_COMPANY_ID");
    params.put("createTimeStamp", "upSales.CREATE_TIME_STAMP");
    params.put("statementId", "upSales.STATEMENT_ID");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return params.get(propertyName);
    });
    return parse;
  }

  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(SQLAliasGenerateUtil.aliasGenerate(PurchaseOrderModel.class, "upSales", null),
              "supplier.NAME AS businessEntityName");
      FROM("T_PUR_PURCHASE_ORDER upSales");
      LEFT_OUTER_JOIN("T_BASE_SUPPLIER AS supplier ON supplier.ID = upSales.BUSINESS_ENTITY_ID");
    }};
  }

  @Override
  protected Class getViewObject() {
    return UpSaleOrderVo.class;
  }


  /**
   * 内部方法  领域对象转vo
   *
   * @param entityList
   * @return
   */
  private List<UpSaleOrderItemVo> transformUpPurchase(List<UpSaleOrderItem> entityList) {
    List<UpSaleOrderItemVo> voList = new ArrayList<>();
    entityList.stream().forEach((entity) -> {
      UpSaleOrderItemVo vo = new UpSaleOrderItemVo();
      ExtBeanUtils.copyProperties(entity, vo);
      voList.add(vo);
    });
    return voList;
  }

  /**
   * 销售订单统计查询
   * @param wrapper
   * @return
   */
  @Override
  public SaleStatisticalAmountVo statisticalAmount(Wrapper wrapper) {
    SQL sql = new SQL() {{
      SELECT(
              "SUM(upSales.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(upSales.TOTAL_IN_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_PUR_PURCHASE_ORDER upSales");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    BaseResolve resolveToSQL = this.getViewWrapperResolve(wrapper);
    sqlString.append(" WHERE 1 = 1").append(resolveToSQL.resolve());
    Map<String, Object> list = MybatisTemplate.selectOne(sqlString.toString());
    SaleStatisticalAmountVo saleStatisticalAmountVo = JSONObject.parseObject(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVo;
  }

  /**
   * 销售订单统计查询
   * @param wrapper
   * @return
   */
  @Override
  public List<SaleStatisticalAmountVo> statisticalAmountByCustomer(Wrapper wrapper) {
    BaseResolve resolveToSQL = this.getViewWrapperResolve(wrapper);
    SQL sql = new SQL() {{
      SELECT(
              "supplier.CODE AS supplierCode",
              "supplier.NAME AS supplierName",
              "SUM(upSales.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(upSales.TOTAL_IN_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_PUR_PURCHASE_ORDER upSales");
      INNER_JOIN("T_BASE_SUPPLIER supplier ON upSales.BUSINESS_ENTITY_ID = supplier.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("supplier.CODE","supplier.NAME");
      ORDER_BY("SUM(upSales.TOTAL_IN_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<SaleStatisticalAmountVo> saleStatisticalAmountVos = JSONArray.parseArray(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVos;
  }

  /**
   * 销售订单统计查询
   * @param wrapper
   * @return
   */
  @Override
  public List<SaleStatisticalAmountVo> statisticalAmountByGoods(Wrapper wrapper) {
    BaseResolve resolveToSQL = this.getViewWrapperResolve(wrapper);
    SQL sql = new SQL() {{
      SELECT(
              "goods.CODE AS goodsCode",
              "goods.NAME AS goodsName",
              "SUM(saleItem.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(saleItem.IN_TOTAL_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_PUR_PURCHASE_ORDER upSales");
      INNER_JOIN("T_PUR_PURCHASE_ORDER_ITEM saleItem ON upSales.ID = saleItem.PURCHASE_ORDER_ID");
      INNER_JOIN("T_BASE_GOODS goods ON saleItem.GOODS_ID = goods.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("goods.CODE","goods.NAME");
      ORDER_BY("SUM(saleItem.IN_TOTAL_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<SaleStatisticalAmountVo> saleStatisticalAmountVos = JSONArray.parseArray(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVos;
  }
}
